/*
 * hrad.S -- startup code for ckcore eval board.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file README.legal in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2009 Hangzhou C-SKY Microsystems co.,ltd.
 * Copyright (C) 2009 Hu junshan (junshan_hu@c-sky.com)
 *
 */

#include <linux/init.h>
#include <linux/threads.h>
#include <asm/setup.h>
#include <asm/ckcore.h>
#include <asm/page.h>
#include <asm/entry.h>
/*
 *	Board setup info.
 */
#define	PHY_MEM_BASE	CK_RAM_BASE	/* Memory base at address 0 */
#define	PHY_MEM_END	CK_RAM_END	/* Memory size 16MB */

//the value is physical address
.export phy_rambase
.export	phy_ramstart
.export	phy_ramend

//Virtual address variable
.export _ramvec
.export swapper_pg_dir
.export empty_bad_page
.export empty_bad_page_table
.export invalid_pte_table

.export _start
//.export _stext

.data

/*
 *	Set up the usable of RAM stuff. Size of RAM is determined then
 *	an initial stack set up at the end.
 */
phy_rambase:
.long	0
phy_ramstart:
.long	0
phy_ramend:
.long	0
_ramvec:
.long	0

swapper_pg_dir:
.fill	4096
empty_bad_page:
.fill	4096
empty_bad_page_table:
.fill	4096
invalid_pte_table:
.fill	4096

.section ".vbr.text","aw"
.align 10
virtual_vec_base:
.fill	128, 4

__HEAD
/*
 *	This is the codes first entry point. This is where it all
 *	begins...
 */
//_stext:
_start:
	.rept   8
	mov     r0, r0
	.endr
	lrw	    r1, 0x8f000140		    /* Init psr value */
	mtcr    r1, psr                 /* Set psr register */

	/*
	 *	Enable internal cache.
	 */
#ifdef CONFIG_CKCORE_INSTRUCTION_CACHE
	//Invalid instruction cache
	movi    r7, 0x11
	mtcr    r7, cr17
	//Enable instruction cache
	mfcr    r7, cr18
	bseti   r7, 2
	mtcr    r7, cr18
#endif

#ifdef CONFIG_CKCORE_DATA_CACHE
	//Invalid Data cache
	movi    r7, 0x12
	mtcr    r7, cr17
	//Enable data cache
	mfcr    r7, cr18
	bseti   r7, 3
	mtcr    r7, cr18
#endif

/*
 * Setup the initial page tables.  We only setup the barest
 * amount which are required to get the kernel running, which
 * generally means mapping in the kernel code.
 *
 */
__create_page_table:

	/*
	 * Create identity mapping for first 32 MB of kernel to
	 * cater for the MMU enable.  This identity mapping
	 * will be removed by paging_init()
	 * 
	 * the mapping relationship:
	 * vaddr 0xC0000000 --> paddr 0x80000000 
	 */

	lrw     r8, PHY_MEM_BASE  //get physical address of start of RAM   
	bmaski  r4, 12           // Page mask 0xFFF (16MB)
	lsli    r4, 13
	movi    r5, 0x0000001E  //C = 011, D = 1, V = 1, G = 0, pfn = 0x0
	bgeni   r6, 19
	or      r6, r5          //C = 011, D = 1, V = 1, G = 0, pfn = 0x1000
	movi    r7, 0x11 
	lsli    r7, 30          //VPN2 = 0xC0000  ASID = 0x0
	bmaski  r9, 25 
	andn    r8, r9
	
	or      r7, r8          // VPN2 is bit 31-12 of phy addr
	lsri    r8, 6	        // get bit 31-12 of phy addr
	or      r5, r8		    //pfn	
	or      r6, r8          //pfn

	SET_CP_MMU
	WR_MPR	r4
	//Initial TLB
	movi    r1, 0        	//Index Reg = 0
	bgeni   r2, 29	 	    //TLBWI
	WR_MEL0	r5
	WR_MEL1	r6
	WR_MEH	r7
	WR_MIR	r1
	WR_MCIR	r2

	mov     r3, r4         //save 16M page mask to used it in follow.
	/*
     * maping kernel code in SRAM, about 8K, base address is 0x10006000
	 * this map relationship is temporary, so we borrow ASID 1.
	 */
	lrw     r8, 0x10006000
	movi    r4, 0          // Page mask 0 (4k)
	movi    r5, 0x00000016 //C = 010, D = 1, V = 1, G = 0, pfn = 0x0
	movi    r6, 0x00000056 //C = 010, D = 1, V = 1, G = 0, pfn = 0x1 
	movi    r7, 0x00000001 //VPN2 = 0x0, ASID = 1	
	bmaski  r9, 13
	andn    r8, r9

	or      r7, r8          // VPN2 is bit 31-12 of phy addr
    lsri    r8, 6           // get bit 31-12 of phy addr
    or      r5, r8          //pfn
    or      r6, r8          //pfn

	SET_CP_MMU
	WR_MPR  r4
	WR_MEL0 r5
    WR_MEL1 r6
    WR_MEH  r7
    bgeni   r2, 28          //TLBWR
	WR_MCIR r2


	/*
	 *  Enable  CPU MMU.
	 */
	mfcr    r7, cr18
	bseti   r7, 0
	bclri   r7, 1
	mtcr    r7, cr18
	
	/*
	 * Enable predict for jump, return stack, and cache write back.
	 */
	mfcr    r7 , cr18
	bseti   r7 , 6
//	bseti   r7 , 5                  /* forecast jump  for ck610  */
//	bseti   r7 , 4                  /* write back for ck610  */
	mtcr    r7 , cr18 
	
	jsri	__create_vector_table   /* P2V, jump from physic address to virtual
										 address */

	/*
	 *	Setup initial vector base table for interrupts and exceptions
	 */
__create_vector_table:
	WR_MPR  r3                      /* change page mask to 16M */
	movi    r3, 0 
	WR_MEH  r3                      /* change ASID to 0 */
	lrw     r1, virtual_vec_base    /* Load pre-defined vbr */
	lrw     r2, _ramvec             /* Load address of _ramvec */
	stw     r1, (r2)                /* Write vbr setting to it */
	mtcr    r1, vbr                 /* Set vbr register with physical address */

	/*
	 * Setup physical memory layout variables. This is the way that
	 * the memory info is passed to the higher level kernel.
	 * Also set up an initial kernel stack at limit of memory.
	 */
	lrw     r1, PHY_MEM_BASE        /* Load pre-defined base */
	lrw     r2, phy_ramstart        /* Load address of phy_rambase */
	stw     r1, (r2)                /* Write the ram base address to it */

	/*
	 *	Determine size of RAM, then set up initial stack.
	 */
	lrw     r1, PHY_MEM_END         /* Load ram end */
	lrw     r2, phy_ramend          /* Load address of phy_ramend */
	stw     r1, (r2)    		    /* Set end ram addr */

	/*
	 *	Zero out the bss region.
	 */
	lrw	    r1, _sbss               /* Get start of bss */
	lrw	    r2, _ebss               /* Get end of bss */
	subu    r2, r1                  /* Calculate size of bss */
	lsri    r2, 2                   /* Size of whole words */

	movi    r3, 0                   /* Set zero value to write */
       
1:
	stw     r3, (r1)                /* Zero next word */
	addi    r1, 4                   /* Increase bss pointer */
	decne   r2                      /* Decrease counter */
	bt      1b                      /* Repeat for all bss */

	/*
	 *	Load the current task stack.
	 */
	lrw     r1, init_thread_union   /* Get address of init_thread_union */
	lrw     r2, THREAD_SIZE         /* 8K memory, 2 page for stack */
	add     r1, r2                  /* Add 2 page offset to r1: 
	                                          task struct pointer */
	mov     r0, r1                  /* Set current task stack pointer */

	/*
	 *	Assember start up done, start code proper.
	 */
	jsri	start_kernel			/* Start Linux kernel */

1:
	br      1b				        /* Should never get here */

